/* ----------------------------------------------------------------------
*
* Copyright (C) 2025 XiaoFei. All rights reserved.
*
* @file:		XiaoZhi_W25Q64.c
* @author:		XiaoFei
* @Date:     	14-January-2025
* @Revision: 	V1
* @Project: 	XiaoFei BSP Library
*
* -------------------------------------------------------------------- */

#include "stm32f10x.h"
#include "XiaoZhi_W25Q64.h"

/* 
* @function: 	W25Q64_Init
*/
void W25Q64_Init(void)
{
	RCC_APB2PeriphClockCmd(W25Q54_RCC_CS,ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = W25Q54_PIN_CS;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(W25Q54_GPIO_CS,&GPIO_InitStructure);
	RCC_APB2PeriphClockCmd(W25Q54_RCC_MOSI,ENABLE);
	GPIO_InitStructure.GPIO_Pin = W25Q54_PIN_MOSI;
	GPIO_Init(W25Q54_GPIO_MOSI,&GPIO_InitStructure);
	RCC_APB2PeriphClockCmd(W25Q54_RCC_CLK,ENABLE);
	GPIO_InitStructure.GPIO_Pin = W25Q54_PIN_CLK;
	GPIO_Init(W25Q54_GPIO_CLK,&GPIO_InitStructure);
	RCC_APB2PeriphClockCmd(W25Q54_RCC_MISO,ENABLE);
	GPIO_InitStructure.GPIO_Pin = W25Q54_PIN_MISO;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init(W25Q54_GPIO_MISO,&GPIO_InitStructure);
	W25Q64_CS(1);
	W25Q64_CLK(0);
}

/* 
* @function: 	W25Q64_SwapByte
* @parameter:	[out] ByteSend				 The byte that will be sent.
* @return:		The byte that will be received.
*/
static unsigned char W25Q64_SwapByte(unsigned char ByteSend)
{
	unsigned char ByteReceive=0x00;
	for(unsigned char i=0;i<8;i++)
	{
		W25Q64_MOSI(!!(ByteSend&(0x80>>i)));
		W25Q64_CLK(1);
		if(W25Q64_MISO)
			ByteReceive|=(0x80>>i);
		W25Q64_CLK(0);
	}
	return ByteReceive;
}

/* 
* @function: 	W25Q64_ReadID
* @parameter:	[out] MID					 The ID number from manufactory.
* @parameter:	[out] DID					 The ID number from device.
*/
void W25Q64_ReadID(unsigned char* MID, unsigned short int* DID)
{
	W25Q64_CS(0);
	W25Q64_SwapByte(W25Q64_JEDEC_ID);
	*MID=W25Q64_SwapByte(W25Q64_DUMMY_BYTE);
	*DID=W25Q64_SwapByte(W25Q64_DUMMY_BYTE);
	*DID<<=8;
	*DID|=W25Q64_SwapByte(W25Q64_DUMMY_BYTE);
	W25Q64_CS(1);
}

/* 
* @function: 	W25Q64_WaitBusy
*/
static void W25Q64_WaitBusy(void)
{
	unsigned int Timeout=100000;
	W25Q64_CS(0);
	W25Q64_SwapByte(W25Q64_RE_REGISTER_1);
	while((W25Q64_SwapByte(W25Q64_DUMMY_BYTE)&0x01)==0x01)
	{
		Timeout--;
		if(Timeout==0)
			break;
	}
	W25Q64_CS(1);
}

/* 
* @function: 	W25Q64_PageProgram
* @parameter:	[in] Address                 The start address of page program.
* @parameter:	[in] DataArray				 The first address of the written array.
* @parameter:	[in] Count					 The size of the written array.
*/
void W25Q64_PageProgram(unsigned int Address, unsigned char* DataArray, unsigned short int Count)
{
	W25Q64_CS(0);
	W25Q64_SwapByte(W25Q64_WRI_EN);
	W25Q64_CS(1);
	W25Q64_CS(0);
	W25Q64_SwapByte(W25Q64_PAGE_PROG);
	W25Q64_SwapByte(Address>>16);
	W25Q64_SwapByte(Address>>8);
	W25Q64_SwapByte(Address);
	for(unsigned short int i=0;i<Count;i++)
		W25Q64_SwapByte(DataArray[i]);
	W25Q64_CS(1);
	W25Q64_WaitBusy();
}

/* 
* @function: 	W25Q64_SectorErase
* @parameter:	[in] Address                 The start address of sector erase.
*/
void W25Q64_SectorErase(unsigned int Address)
{
	W25Q64_CS(0);
	W25Q64_SwapByte(W25Q64_WRI_EN);
	W25Q64_CS(1);
	W25Q64_CS(0);
	W25Q64_SwapByte(W25Q64_SECTOR_4KB);
	W25Q64_SwapByte(Address >> 16);
	W25Q64_SwapByte(Address >> 8);
	W25Q64_SwapByte(Address);
	W25Q64_CS(1);
	W25Q64_WaitBusy();
}

/* 
* @function: 	W25Q64_ReadData
* @parameter:	[in] Address                 The start address of reading data.
* @parameter:	[out] DataArray				 The first address of the data to be read.
* @parameter:	[in] Count					 The size of the data to be read.
*/
void W25Q64_ReadData(unsigned int Address, unsigned char* DataArray, unsigned int Count)
{
	W25Q64_CS(0);
	W25Q64_SwapByte(W25Q64_READ_DATA);
	W25Q64_SwapByte(Address>>16);
	W25Q64_SwapByte(Address>>8);
	W25Q64_SwapByte(Address);
	for(unsigned int i=0; i<Count; i++)
		DataArray[i] = W25Q64_SwapByte(W25Q64_DUMMY_BYTE);
	W25Q64_CS(1);
}


